package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.common.constants.WemediaConstants;
import com.heima.common.exception.CustomException;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.feign.article.IArticleClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.GreenScanService;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Auther: Tangguo
 * @Date: 2023-06-11  14:23
 */


@Service
@Slf4j
@Transactional
@SuppressWarnings("all")//去除所有警告
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private GreenScanService greenScanService;

    @Autowired
    private WmUserMapper wmUserMapper;

    @Autowired
    private WmChannelMapper wmChannelMapper;

    @Autowired
    private IArticleClient articleClient;

    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private FileStorageService fileStorageService;


    @Autowired
    private Tess4jClient tess4jClient;

    /**
     * 自媒体文章审核
     *
     * @param id 自媒体文章id
     */
    @Override
    public void autoScanWmNews(Integer id) {
        //1.根据文章id查询数据库文章信息
        WmNews wmNews=wmNewsMapper.selectById(id);
        if(wmNews==null|| StringUtils.isBlank(wmNews.getContent())){
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //2.提取文章中文字和图片
        Map<String,Object> map=handleTextAndImage(wmNews);

        //自定义敏感词管理
        boolean isSensitive = handleSensitiveScan((String) map.get("text"), wmNews);
        if(!isSensitive) return;
        //3.审核文字
        boolean isTextScan=scanText(map.get("text").toString(),wmNews);
        if(!isTextScan)return;
        //4.审核图片
        boolean isImageScan=scanImage((List<String>)map.get("image"),wmNews);
        if(!isImageScan)return;

        try {
            //5.远程调用article微服务，进行app文章保存
            ResponseResult result=saveArticle(wmNews);
            if (result.getCode()==200){
                //调用远程article成功后，需要回填wm_news表中的article_id字段
                wmNews.setArticleId((Long) result.getData());
                wmNews.setReason("审核成功");
                wmNews.setStatus(WmNews.Status.PUBLISHED.getCode());
                wmNewsMapper.updateById(wmNews);
            }else {
                throw new RuntimeException("WmNewsAutoScanServiceImpl --- 同步app文章失败!");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("WmNewsAutoScanServiceImpl --- 同步app文章失败!");
        }


    }

    /**
     * 创建app端的文章信息
     * @param wmNews :
     * @return ResponseResult
     */
    @Override
    public ResponseResult creatAppArticle(WmNews wmNews) {
        //1.参数校验
        if(wmNews==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        ArticleDto articleDto = new ArticleDto();
        BeanUtils.copyProperties(wmNews,articleDto);
        //文章的布局
        articleDto.setLayout(wmNews.getType());
        //频道
        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
        if(wmChannel != null){
            articleDto.setChannelName(wmChannel.getName());
        }

        //作者
        articleDto.setAuthorId(wmNews.getUserId().longValue());
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        if(wmUser != null){
            articleDto.setAuthorName(wmUser.getName());
        }

        //设置文章id
        if(wmNews.getArticleId() != null){
            articleDto.setId(wmNews.getArticleId());
        }
        articleDto.setCreatedTime(new Date());

        ResponseResult result = articleClient.saveArticle(articleDto);
        return result;
    }

    /**
     * 自管理的敏感词审核
     * @param text:
     * @param wmNews:
     * @return boolean
     */
    private boolean handleSensitiveScan(String text, WmNews wmNews) {
        if(StringUtils.isNotBlank(text)) {
            boolean flag = true;

            //获取所有的敏感词 --先从redis中获取
            List<String> sensitiveList = (List<String>) redisTemplate.opsForValue().get("Sensitive");

            if (sensitiveList == null) {
                //redis缓存没有，需要查询数据库，然后储存到缓存中
                List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(Wrappers.<WmSensitive>lambdaQuery().select(WmSensitive::getSensitives));
                sensitiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
                //存入redis中
                redisTemplate.opsForValue().set("Sensitive", sensitiveList);
            }

            //初始化敏感词库
            SensitiveWordUtil.initMap(sensitiveList);

            //查看文章中是否包含敏感词
            Map<String, Integer> map = SensitiveWordUtil.matchWords(text);
            if (map.size() > 0) {
                flag = false;
                wmNews.setStatus(WmNews.Status.FAIL.getCode());
                wmNews.setReason("审核失败：文章存在违规信息" + map);
                wmNewsMapper.updateById(wmNews);
            }

            return flag;
        }

        return false;

    }

    /**
     * 远程调用article微服务，实现wm_news到ap_article的数据同步
     * @param wmNews:
     * @return ResponseResult
     */
    private ResponseResult saveArticle(WmNews wmNews) {
        //准备一个articleDto
        ArticleDto articleDto=new ArticleDto();
        //从wmNews中将大部分属性拷贝到dto
        BeanUtils.copyProperties(wmNews,articleDto);
        //部分属性需要单独处理
        //1.作者id
        articleDto.setAuthorId(wmNews.getUserId().longValue());
        //2.作者名称
        WmUser wmUser=wmUserMapper.selectById(wmNews.getUserId());
        if(wmUser!=null){
            articleDto.setAuthorName(wmUser.getName());
        }
        //3.文章布局
        articleDto.setLayout(wmNews.getType());
        //4.频道名称
        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
        if(wmChannel!=null){
            articleDto.setAuthorName(wmChannel.getName());
        }
        //5.文章id
        if(wmNews.getArticleId()!=null){
            //说明是对之前发布过的文章进行修改，这时候需要给app端携带article_id
            articleDto.setId(wmNews.getArticleId());
        }

        ResponseResult result=articleClient.saveArticle(articleDto);

        return result;
    }

    /**
     * 审核文章中的图片
     * @param image:
     * @param wmNews:
     */
    private boolean scanImage(List<String> image, WmNews wmNews) {
        //假设文章能审核通过
        boolean flag=true;
        try{
            for (String url : image) {
                ////图片识别文字审核---begin-----
                // 本地文件路径
                byte[] imgData = fileStorageService.downLoadFile(url);
                //从byte[]转换为butteredImage
                ByteArrayInputStream in = new ByteArrayInputStream(imgData);
                BufferedImage img = ImageIO.read(in);
                //1. 先通过tess4j进行OCR操作，提取图片中的文字，先审核文字
                String textInImage = tess4jClient.doOCR(img);
                //2.
                boolean isSensitive= handleSensitiveScan(textInImage, wmNews);
                if(!isSensitive) {
                    //未通过自定义审核
                    flag=false;
                    break;
                }
                //调用百度云API进行内容审核
                Map map=greenScanService.scanImage(url);
                //不通过，修改文章状态
                if(map.get("conclusionType")== WemediaConstants.BAIDU_SCAN_NOT_PASS){
                    flag=false;
                    wmNews.setStatus(WmNews.Status.FAIL.getCode());
                    wmNews.setReason("审核失败：文章图片存在违规信息");
                    wmNewsMapper.updateById(wmNews);
                    break;
                }
                //疑似，修改文章状态
                if(map.get("conclusionType")== WemediaConstants.BAIDU_SCAN_SUSPECTED){
                    flag=false;
                    wmNews.setStatus(WmNews.Status.ADMIN_AUTH.getCode());
                    wmNews.setReason("待人工审核：文章图片疑似存在违规信息");
                    wmNewsMapper.updateById(wmNews);
                    break;
                }

            }

        }catch (Exception e){
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 审核文章中的纯文本内容
     * @param text:
     * @param wmNews:
     */
    private boolean scanText(String text, WmNews wmNews) {
        boolean flag=true;
        try{
            //调用百度云API进行内容审核
            Map map=greenScanService.scanText(text);
            //不通过，修改文章状态
            if(map.get("conclusionType")== WemediaConstants.BAIDU_SCAN_NOT_PASS){
                flag=false;
                wmNews.setStatus(WmNews.Status.FAIL.getCode());
                wmNews.setReason("审核失败：文章存在违规信息");
                wmNewsMapper.updateById(wmNews);
            }
            //疑似，修改文章状态
            if(map.get("conclusionType")== WemediaConstants.BAIDU_SCAN_SUSPECTED){
                flag=false;
                wmNews.setStatus(WmNews.Status.ADMIN_AUTH.getCode());
                wmNews.setReason("待人工审核：文章疑似存在违规信息");
                wmNewsMapper.updateById(wmNews);
            }

        }catch (Exception e){
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 提取文章中文字和图片
     * @ptiam wmNews:
     * @return Map<String,Object>
     */
    private Map<String, Object> handleTextAndImage(WmNews wmNews) {
        if(wmNews!=null && StringUtils.isNotBlank(wmNews.getContent())){
            String content=wmNews.getContent();
            JSONArray jsonArray = JSON.parseArray(content);

            //定义一个StringBuilder容器用来存放所有的文字
            StringBuilder builder = new StringBuilder(wmNews.getTitle());
            builder.append(wmNews.getLabels());

            //定义一个ArrayList容器用来存放所有的图片
            List<String> list=new ArrayList<>();

            //1.提取文章内容在中所有文字和图片
            for (Object json : jsonArray) {
                JSONObject jsonObject = JSON.parseObject(json.toString());
                if(jsonObject.get("type").equals("text")){
                    //提取文字
                    builder.append(jsonObject.get("value").toString());
                }

                if(jsonObject.get("type").equals("image")){
                    //提取图片
                    list.add(jsonObject.get("value").toString());
                }
            }

            //2.提取封面图片
            String images=wmNews.getImages();
            if(StringUtils.isNotBlank(images)){
                String[] split = images.split(",");
                list.addAll(Arrays.asList(split));
            }

            //3.封装结果map并返回
            Map<String,Object> map=new HashMap<>();
            map.put("text",builder.toString());
            map.put("image",list);
            return map;
        }
        return null;
    }
}
